package org.ccay.message.service.impl;

import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import javax.inject.Inject;
import javax.inject.Named;

import org.ccay.async.AsyncMessage;
import org.ccay.async.IMessageSender;
import org.ccay.core.base.PageVO;
import org.ccay.core.base.PagedResult;
import org.ccay.core.exception.ApplicationException;
import org.ccay.core.log.CcayLoggerFactory;
import org.ccay.core.log.ILogger;
import org.ccay.core.registry.RegistryItem;
import org.ccay.core.request.impl.RequestContext;
import org.ccay.core.util.DaoUtil;
import org.ccay.core.util.DateUtil;
import org.ccay.message.PushMessageApplicationException;
import org.ccay.message.PushMessageVO;
import org.ccay.message.dao.IPushMessageDao;
import org.ccay.message.service.IPushMessageService;
import org.ccay.registry.exception.RegistryNotFindException;
import org.ccay.registry.util.RegistryQueryUtil;

/**
 * 
 * 消息推送服 
 * 
 * @author chaowangbang
 * @since 2012-11-5
 */
@Named
public class PushMessageService implements IPushMessageService {
	
	//private static int NOT_SENT = 0;
	private static final int HAS_SENT = 1;
	//private static final int NOT_READ = 2;
	private static final int HAS_READ = 3;
	
	private static final String NOTREADFLAG = "NotReadMessageCleanDuration";
	private static final String HASREADFLAG = "HasReadMessageCleanDuration";
	
	/**
	 * TRUE 的字符串表示形式 
	 */
	public static final String CODE_TURE = "1";
	
	/**
	 * FALSE 的字符串表示形式 
	 */
	public static final String CODE_FALSE = "0";
	
	private static final String PUSHMESSAGE = "PushMessage";
	
	private static final Pattern pushMsgRegexp  = Pattern.compile("\\S*\"pushMsg\":\\{([a-zA-Z0-9:\",_-]+)\\}\\S*");
	
	@Inject
	private IPushMessageDao ipushMessageDao;

	/** 消息推送服 **/
	@Inject
	private IMessageSender messageSender;
	
	
//	@Inject
//	private IPersonalizedSettingService personlizedSettingService;
	
	private final ILogger logger = CcayLoggerFactory.getLogger(PushMessageService.class);
	
	/**
	 * 取用户报 
	 */
	public static final String FormatConvertException = "ccay.pushMessage.00010005";
	/*
	 * (non-Javadoc)
	 * @see org.ccay.message.service.IPushMessageService#findPagedMessageList(org.ccay.message.PushMessageVO, org.ccay.core.base.PageVO)
	 */
//	@CcayOperation(policy=SecurityPolicy.AllSystemUser)
	public PagedResult<PushMessageVO> usePagedMessageList(PushMessageVO messageVO, PageVO pageVO) throws ApplicationException {
		messageVO.setMessageReceiver(String.valueOf(RequestContext.getCurrent().getUser().getUserId()));
		PagedResult<PushMessageVO> pushPagedMessageVOs = ipushMessageDao.usePagedMessageList(messageVO, pageVO);
		this.updateMessageListStatus(pushPagedMessageVOs.getResult(),HAS_READ);
		return pushPagedMessageVOs;
	}

	/*
	 * (non-Javadoc)
	 * @see org.ccay.message.service.IPushMessageService#createMessage(org.ccay.message.PushMessageVO)
	 */
//	@CcayOperation(policy=SecurityPolicy.AllSystemUser)
	public void createMessage(PushMessageVO messageVO) throws ApplicationException {
		DaoUtil.assertEffected(ipushMessageDao.createMessage(messageVO), PUSHMESSAGE);
	}

	/*
	 * (non-Javadoc)
	 * @see org.ccay.message.service.IPushMessageService#findMessageList(org.ccay.message.PushMessageVO)
	 */
//	@CcayOperation(policy=SecurityPolicy.AllSystemUser)
	public List<PushMessageVO> useMessageList(PushMessageVO messageVO) throws ApplicationException {
//		messageVO.setMessageReceiver(String.valueOf(RequestContext.getCurrent().getUser().getUserId()));
//		List<PushMessageVO> pushMessageVOs =ipushMessageDao.useMessageList(messageVO);
//		this.updateMessageListStatus(pushMessageVOs,HAS_SENT);
//		// 自定义消息添加到系统的消息中
//		PushMessageArgs args = new PushMessageArgs();
//		// 执行所有的IPushMessageHandler的实现类
//		EventUtil.dispatch(IPushMessageHandler.class, this, args);
//		// 得到的消息list添加到pushMessageVOs
//		if(!CollectionUtil.isNullOrEmpty(args.getMessageList())){
//			pushMessageVOs.addAll(args.getMessageList());
//		}
		return Collections.emptyList();
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.ccay.message.service.IPushMessageService#findMessageList(org.ccay.message.PushMessageVO)
	 */
//	@CcayOperation(policy=SecurityPolicy.AllSystemUser)
	public List<PushMessageVO> usePushMessageList(PushMessageVO messageVO) throws ApplicationException {
		messageVO.setMessageReceiver(String.valueOf(RequestContext.getCurrent().getUser().getUserId()));
		List<PushMessageVO> pushMessageVOs =ipushMessageDao.useMessageList(messageVO);
		this.updateMessageListStatus(pushMessageVOs,HAS_SENT);
		return pushMessageVOs;
	}

	/*
	 * (non-Javadoc)
	 * @see org.ccay.message.service.IPushMessageService#deleteMessage(org.ccay.message.PushMessageVO)
	 */
//	@CcayOperation(policy=SecurityPolicy.AllSystemUser)
	public void deleteMessage(PushMessageVO messageVO) throws ApplicationException {
		DaoUtil.assertEffected(ipushMessageDao.deleteMessage(messageVO), PUSHMESSAGE);
	}

	/*
	 * (non-Javadoc)
	 * @see org.ccay.message.service.IPushMessageService#updateMessage(org.ccay.message.PushMessageVO)
	 */
//	@CcayOperation(policy=SecurityPolicy.AllSystemUser)
	public void updateMessage(PushMessageVO messageVO) throws ApplicationException {
		DaoUtil.assertEffected(ipushMessageDao.updateMessage(messageVO), PUSHMESSAGE);
	}

	/*
	 * (non-Javadoc)
	 * @see org.ccay.message.service.IPushMessageService#updateMessageList(java.util.List)
	 */
//	@CcayOperation(policy=SecurityPolicy.AllSystemUser)
	public void updateMessageList(List<PushMessageVO> messageVOs) throws ApplicationException {
		ipushMessageDao.updateMessageList(messageVOs);		
	}
	
	/**
	 * 更新结果集推送状 
	 * @author chaowangbang
	 * @since 2012-11-9
	 * @param messageList
	 * @param messageStatus
	 * @throws ApplicationException
	 */
	public void updateMessageListStatus(List<PushMessageVO> messageList,int messageStatus) throws ApplicationException {
		if(!messageList.isEmpty()){
			PushMessageVO messageVO = new PushMessageVO();
			messageVO.setMessageFlag(messageStatus);
			ipushMessageDao.updateMessageListStatus(messageList,messageVO);			
		}
	}
	/**
	 * 更新消息为已 
	 */
//	@CcayOperation(policy=SecurityPolicy.AllSystemUser)
	public void updateMessageRead(Integer messageId) throws ApplicationException {
		if(messageId!=null && messageId>0){
			PushMessageVO messageVO = new PushMessageVO();
			messageVO.setMessageId(messageId);
			messageVO.setMessageFlag(HAS_READ);
			ipushMessageDao.updateMessageStatus(messageVO);
		}
	}

	/**
	 * 查询系统里面消息数量大于100的消息接收 
	 */
	public List<PushMessageVO> findUselessMessageList() throws ApplicationException {
		return ipushMessageDao.findUselessMessageList();
	}

	/**
	 * 删除某个用户消息大于100条的记录
	 */
	public void deleteUserMessage(PushMessageVO messageVO) throws ApplicationException {
		ipushMessageDao.deleteUserMessage(messageVO);
	}

	/**
	 * 发送异步推送消 
	 */
	public void sendAsyncMessage(PushMessageVO messageVO){	
		String messageType = messageVO.getMessageType();
		//如果验证 次消息不发送给当前人，那么直接泛返
		if(!checkMessageEnable(messageType)){
			return;
		}
		AsyncMessage asyncMessage = new AsyncMessage("PushMessage");
		asyncMessage.setContent(messageVO);
		messageSender.send(asyncMessage);
	}
	/**
	 * 检查消息是否需要发  和个性化关联
	 * @param messageType
	 * @return
	 * Created013-3-25
	 * @author chaowangbang
	 */
	public  boolean checkMessageEnable(String messageType){
		// 消息推送全局开关开启和具体消息类型的开关开启才发送消
		if (!RegistryQueryUtil.getBooleanValue("Ccay.GlobalParamters.EnablePushMessage")) {
			logger.warn("Global messages mark not enable, please check the registry : GlobalParameters.EnablePushMessage");
			return false;
		}
		
		RegistryItem messageTypeVO = null;
		try{
			messageTypeVO = RegistryQueryUtil.get("App.PushMessage."+messageType);
		}catch(RegistryNotFindException e){
			logger.warn("Can not found the {0} type of push message in registry config, please check the registry : App.PushMessage.{0}", messageType);
			return false;
		}
		//数据字段是否没有开启当前消
		
		String localEnable = CODE_FALSE;
		try{
			localEnable = RegistryQueryUtil.getValue("App.PushMessage."+messageType+".Enabled");
		}catch(RegistryNotFindException e){
			//ignore
		}
		if(!CODE_TURE.equals(localEnable)){
			logger.warn("the {0} type of push message mark not enable, please check the registry : App.PushMessage.{0}.Enabled}", messageType);
			return false;
		}
		/**
		 * 根据个性化检不需要发送消那么直接返回
		 */
		return checkSendMessage4Personalized(messageType);
	}
	
	/**
	 * 根据个性化信息 检查是否需要发送消
	 * @param messageType
	 * @return
	 * Created013-3-24
	 * @author chaowangbang
	 */
	private boolean checkSendMessage4Personalized(String messageType){
		//TODO checkSendMessage4Personalized
//		PersonalizedSettingVO queryVO =  new PersonalizedSettingVO();
//		queryVO.setSettingKey("global");
//		queryVO.setUserId(queryVO.getCurrentUserId());
//		boolean send = true;
//		/**
//		 * 判断个性化是否有当前消息推送的配置
//		 */
//		try {
//			List<PersonalizedSettingVO> personlizeds = personlizedSettingService.findUserSettings(queryVO);
//			//如果当前人个性化不存那么全部发
//			if(CollectionUtil.isNullOrEmpty(personlizeds) || null == personlizeds.get(0)){
//				return true;
//			}
//			//从个性化获取pushmsg的配
//			logger.debug("PersonalizedSetting =" + personlizeds.get(0).getSettingContent());
//			String msgString = StringUtil.returnExistStr(personlizeds.get(0).getSettingContent(),pushMsgRegexp);
//			if(StringUtil.isNullOrEmpty(msgString)){
//				return true;
//			}
//			Map<String,Object> msgMap =  JsonUtil.stringToObject("{"+msgString+"}", Map.class);//JSon数据转换为map
//			send = this.checkPersonalizedSeting(msgMap,messageType);
//		}catch (ApplicationException e) {
//			//如果获取配置  那么只记录日  并且发送推
//			logger.error("Search global messages error!",e);
//		} catch (IOException e) {
//			//如果获取配置  那么只记录日  并且发送推
//			logger.error("personlizeds messages json error!",e);
//		} 
//		return send;
		return true;
	}
	/**
	 * 检查信息中的配置是否满足要求
	 * @param msgMap
	 * @param messageType
	 * @return
	 * Created：2013-4-19
	 * @author chaowangbang
	 */
	private boolean checkPersonalizedSeting(Map<String,Object> msgMap,String messageType){
		//个性化页面  取消了消息推
		if("0".equals(msgMap.get("enable"))){
			return false;
		}
		String disabledMsg = ","+msgMap.get("items")+",";
		//如果当前否则其中的配那么不发送消
		if(",All,".equals(disabledMsg)){
			logger.warn("PersonalizedSetting " + messageType +" don't send!");
			return false;
		}
		//如果当前否则其中的配那么不发送消
		if(disabledMsg.indexOf(","+messageType+",")!=-1){
			logger.warn("PersonalizedSetting " + messageType +" don't send!");
			return false;
		}
		return true;
	}
	/**
	 * 定时任务调用，根据消息标记已读和未读来清理用户的消息列表，如果未配置数据字典相关选项，那么已读消息默认清5天，未读消息默认清理1个月
	 */
	public void deleteUselessMessage() throws ApplicationException{
		Map<String, String> cleanMessageMap = getCleanMessageRegistrys();
		//已读消息清理期限
		Date hasReadMessageCleanDuration = null;
		//未读消息清理期限
		Date notReadMessageCleanDuration = null;
		if (cleanMessageMap.isEmpty()) {
			hasReadMessageCleanDuration = DateUtil.getDateBefore(new Date(), 15);
			notReadMessageCleanDuration = DateUtil.getMonthBefore(new Date(), -1); // 转换后的结束时间
		} else {
			try {
				hasReadMessageCleanDuration = DateUtil.getDateBefore(new Date(),Integer.parseInt(cleanMessageMap.get(HASREADFLAG)));
				notReadMessageCleanDuration = DateUtil.getDateBefore(new Date(),Integer.parseInt(cleanMessageMap.get(NOTREADFLAG)));
			} catch (NumberFormatException e) {
				throw new PushMessageApplicationException(FormatConvertException, e);
			}
		}
		String appName = RequestContext.getCurrent().getApplication().getAppName();
		ipushMessageDao.deleteUselessMessage(hasReadMessageCleanDuration, notReadMessageCleanDuration, appName);
	}
	
	/**
	 * 获取清理消息配置的数据字
	 * @author chaowangbang
	 * @since 2013-3-5
	 * @return
	 * @throws ApplicationException
	 */
	private Map<String, String> getCleanMessageRegistrys() throws ApplicationException {
//		List<RegistryVO> cleanMessageRegistrys = registryQueryService.findRegistryListByParentPath("App.PushMessage.Global", false);
//		Map<String, String> cleanMessageMap = new HashMap<String, String>();
//		for (RegistryVO rv : cleanMessageRegistrys) {
//			cleanMessageMap.put(rv.getName(), rv.getValue());
//		}
//		return cleanMessageMap;
		return new HashMap<String,String>();
	}
	
	/**
	 * 查询未读的消息个数
	 * @param messageVO
	 * @param includeOverdue 是否包含过期
	 * @return
	 * @author chaowangbang
	 */
	public int findNewMessageCount(PushMessageVO messageVO,boolean includeOverdue){
		return ipushMessageDao.findNewMessageCount(messageVO,includeOverdue);
	}
}
